/*

  xmunipack - plplot backend

  Copyright © 1997-2010 F.Hroch (hroch@physics.muni.cz)

  This file is part of Munipack.

  Munipack is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.
  
  Munipack is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
  
  You should have received a copy of the GNU General Public License
  along with Munipack.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "xmunipack.h"
#include <wx/wx.h>
#include <plplot/wxPLplotwindow.h>
#include <vector>
#include <limits>

#ifdef WX_TEMP_HAVE_FREETYPE_IS_ON
#define PLPLOT_OPTIONS wxPLPLOT_BACKEND_GC|wxPLPLOT_DRAW_TEXT|wxPLPLOT_SMOOTH_TEXT|wxPLPLOT_FREETYPE
#else
#define PLPLOT_OPTIONS wxPLPLOT_BACKEND_GC|wxPLPLOT_DRAW_TEXT
#endif

using namespace std;


//BEGIN_EVENT_TABLE(MuniPlotHisto, wxPLplotwindow)
//  EVT_SIZE(MuniPlotHisto::OnSize)
//END_EVENT_TABLE()

// -- MuniPlotHisto  --------------------------------------------

MuniPlotHisto::MuniPlotHisto(wxWindow *w, bool t):
  wxPLplotwindow(w,wxID_ANY,wxDefaultPosition,wxDefaultSize,wxWANTS_CHARS,
		 PLPLOT_OPTIONS),
		 //	 wxPLPLOT_BACKEND_GC|wxPLPLOT_DRAW_TEXT|wxPLPLOT_SMOOTH_TEXT),
  itt_plot(false),axes(t),hmax(1),xmin(0.0),xmax(0.0),
  bestsize(axes ? wxSize(300,185) : wxSize(162,100))
{
  Plot();
}

wxSize MuniPlotHisto::DoGetBestSize() const
{
  //  return wxSize(300,185);
  //  return wxSize(10,10);
  return bestsize;
}

/*
void MuniPlotHisto::SetAxes(bool t)
{
  axes = t;

  if( axes )
    bestsize = wxSize(300,185);
  else
    bestsize = wxSize(1,1);
}
*/

void MuniPlotHisto::SetItt(const FitsItt& i) 
{ 
  itt_plot = true;
  itt = i;
  Plot();
  //  itt = i;
  //  Refresh();
}

void MuniPlotHisto::SetHisto(const FitsHisto& hl)
{
  hlist.clear();
  hlist.push_back(hl);
  SetHisto(hlist);
  //Refresh();
  //  Plot();
}

void MuniPlotHisto::SetHisto(const std::vector<FitsHisto>& h)
{
  vector<FitsHisto> hs = h;
  //  hlist = h;
  hlist.clear();
  for(vector<FitsHisto>::const_iterator k = hs.begin(); k != hs.end();++k)
    if( k->IsOk() )
      hlist.push_back(*k);

  // search for maximum in histogram
  hmax = 0;
  for(vector<FitsHisto>::const_iterator k = hlist.begin(); k!=hlist.end();++k){
    FitsHisto hist = *k;  
    for(int i = 0; i < hist.NBins(); i++ ) {
      if( hist.Hist(i) > hmax )
        hmax = hist.Hist(i);
    }
  }

  // set range of values
  /*
  FitsHisto hist = hlist[hlist.size() == 1 ? 0 : 1];
  wxASSERT(hist.IsOk());
  xmin = hist.CentsMin();
  xmax = hist.CentsMax();
  */

  xmin = numeric_limits<double>::max();
  xmax = -xmin;
  for(vector<FitsHisto>::const_iterator k = hlist.begin(); k!=hlist.end();++k){
    FitsHisto hist = *k;  
    if( xmin > hist.Cents(0) )
      xmin = hist.Cents(0);
    if( xmax < hist.Cents(hist.NBins()-1) )
      xmax = hist.Cents(hist.NBins()-1);
  }

  /*
  xmin = hist.Cents(0);
  for(int i = 0; i < hist.NBins()-1; i++)
    if( hist.Hist(i) > 0 ) {
      xmin = hist.Cents(i);
      break;
    }

  xmax = hist.Cents(hist.NBins()-1);
  for(int i = hist.NBins()-1; i > 0 ; i--)
    if( hist.Hist(i) > 0 ) {
      xmax = hist.Cents(i);
      break;
    }
  */

  /*
  if( hlist.size() == 1 ) {
    FitsHisto hist = hlist[0];  
    xmin = hist.Cents(0);
    xmax = hist.Cents(hist.NBins()-1);
  }
  else if ( hlist.size() > 1 ) {
    FitsHisto hist = hlist[1];  
    xmin = hist.Cents(0);
    xmax = hist.Cents(hist.NBins()-1);
  }
  */

  //  wxLogDebug(_("/// %d %d %d"),xmin,xmax,hmax); 

  Plot();
}

void MuniPlotHisto::Plot()
{
  wxColour cb = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWFRAME);
  wxColour ct = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
  wxColour ht = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNHIGHLIGHT);

  wxPLplotstream* pls = GetStream();
  pls->adv(0);
  //  pls->sfont(PL_FCI_SANS,PL_FCI_ITALIC,PL_FCI_MEDIUM);
  pls->schr(0.0,2.0);

  //  PLUNICODE fn;
  //  pls->gfci(fn);
  //  wxLogDebug(_("%x"),fn);
  //  pls->sfci(0x80000004);
  //  PLFLT u,v;
  //  pls->gchr(u,v);
  //  wxLogDebug(_("%f %f"),u,v);


  pls->scol0a(0,cb.Red(),cb.Green(),cb.Blue(),1.0);
    pls->scol0a(1,ct.Red(),ct.Green(),ct.Blue(),1.0);
    /*
  if( axes )
    pls->scol0a(1,ct.Red(),ct.Green(),ct.Blue(),1.0);
  else
    pls->scol0a(1,0,0,0,0.0);  
    */
  //  pls->scol0a(0,255,255,255,1.0);
  //    pls->scol0a(1,0,0,0,1.0);

  if( hlist.empty() ) {
    pls->vpor(0.1, 0.9, 0.3, 0.99);
    pls->wind(-0.5, 10.5, 0.0, 1.0);
    pls->box("bcnt",0.0,0.0,"bct",0.0,0.0);
  }
  else {

    pls->scol0a(2,0,0,255,0.2);
    pls->scol0a(3,0,255,0,0.2);
    pls->scol0a(4,255,0,0,0.2);
    pls->scol0a(5,170,170,170,0.2);

    pls->scol0a(12,0,0,255,1.0);
    pls->scol0a(13,0,255,0,1.0);
    pls->scol0a(14,255,0,0,1.0);
    pls->scol0a(15,170,170,170,1.0);
    

    if( axes ) {
      pls->vpor(0.1, 0.9, 0.2, 0.9);
      pls->wind(0.95*xmin, 1.05*xmax, 0.0, 1.1*hmax);
      pls->box("bcnt",0.0,0.0,"bct",0.0,0.0);
    }
    else {
      pls->vpor(0.0, 1.0, 0.0, 1.0);
      pls->wind(xmin, xmax, 0.0, 1.1*hmax);
      //      pls->box("bcnt",0.0,0.0,"bct",0.0,0.0);
    }

    //  pls->ptex((xmin+xmax)/2.0,hmax/2.0,0.0,0.0,0.0,"fsdgfsdgsdgs 1 5 7 9");

    
    //    pls->env(1.0*xmin, 1.0*xmax, 0.0, 1.1*hmax,0,0);

    vector<int> c;
    if( hlist.size() == 1 )
      c.push_back(5);
    else {
      c.push_back(2);
      c.push_back(3);
      c.push_back(4);
    }
    
    for(size_t i = 0; i < hlist.size(); i++) {

      FitsHisto hist = hlist[i];
      
      // plot rectangles
      pls->col0(c[i]);
      for(int l = 0; l < hist.NBins()-1; l++) {
	PLFLT x[4], y[4];
	x[0] = hist.Cents(l);
	y[0] = 0.0;
	x[1] = hist.Cents(l);
	y[1] = hist.Hist(l);
	x[2] = hist.Cents(l+1);
	y[2] = hist.Hist(l+1);
	x[3] = hist.Cents(l+1);
	y[3] = 0.0;
	pls->fill( 4, x, y );
      }

      // plot line
      const size_t n = hist.NBins();
      PLFLT        x[n],y[n];
      for(size_t l = 0; l < n; l++) {
	x[l] = hist.Cents(l);
	y[l] = hist.Hist(l);
      }
      pls->col0(c[i]+10);
      pls->wid(2);
      pls->line(n,x,y);
    }
  }


  // plot ITT
  if( itt_plot /*itt.IsOk()*/ ) {
    PLFLT p_xmin, p_xmax, p_ymin, p_ymax;
    pls->gvpw (p_xmin, p_xmax, p_ymin, p_ymax);
    int npoints = 20;
    double step = (p_xmax - p_xmin)/npoints;
    PLFLT x[npoints],y[npoints];
    for(int i = 0; i < npoints; i++) {
      double f = p_xmin + i*step;
      unsigned char c = itt.Fscale(f);
      x[i] = f;
      y[i] = float(c)/255.0*hmax;
    }
    pls->scol0a(9,ht.Red(),ht.Green(),ht.Blue(),0.5);
    //    pls->scol0(9,ht.,0,0);
    //    pls->col0(9);
    //    PLFLT r[2] = {0.0,1.0}, g[2] = {0.0,1.0}, b[2] = {0.0,1.0},
    //	i[2] = {0.0, 0.0};
	//    pls->scmap1l(true,2,i,r,g,b,NULL);
    pls->col0(9);
    pls->wid(3);
    pls->line(npoints,x,y);
    pls->col0(1);
    pls->poin(npoints,x,y,9);
  }

  pls->wid(0);
  pls->col0(1);

  //  pls->end();


//   const size_t nh = 50;
//   PLFLT         hx[nh],hr[nh],hg[nh],hb[nh];
//     for ( size_t i = 0; i < nh; i++ ) {
//       double t = (i - 25.0)/10.0;
//       hx[i] = t;
//       hr[i] = exp(-(t-1)*(t-1)/2.0);
//       hg[i] = exp(-(t-0)*(t-0)/2.0);
//       hb[i] = exp(-(t+1)*(t+1)/2.0);
//       //      wxLogDebug(_("%f %f"),hx[i],hy[i]);
//     }



//   //  pls->env( -3.0, 3.0, 0.0, 1.0, 0, 0 );
  
//   PLFLT def,ht;
//   pls->gchr(def,ht);
//   wxLogDebug(_("%f %f "),def,ht);

//   pls->schr(0.0,3.0);

    

//     pls->col0(2);

//     for ( size_t i = 0; i < nh-1; i++ ) {
//       PLFLT x[4], y[4];
//       x[0] = hx[i];
//       y[0] = 0.0;
//       x[1] = hx[i];
//       y[1] = hr[i];
//       x[2] = hx[i+1];
//       y[2] = hr[i+1];
//       x[3] = hx[i+1];
//       y[3] = 0.0;
//       plfill( 4, x, y );
//     }

//     pls->col0(5);    
//     pls->wid( 2 );
//     pls->line( nh, hx, hr );

//     pls->col0(4);
//     pls->wid( 1 );
//     for ( size_t i = 0; i < nh-1; i++ ) {
//       PLFLT x[4], y[4];
//       x[0] = hx[i];
//       y[0] = 0.0;
//       x[1] = hx[i];
//       y[1] = hb[i];
//       x[2] = hx[i+1];
//       y[2] = hb[i+1];
//       x[3] = hx[i+1];
//       y[3] = 0.0;
//       plfill( 4, x, y );
//     }
    
//     pls->col0(7);
//     pls->wid( 2 );
//     pls->line( nh, hx, hb );

  
//   pls->ptex(0.0,0.5,0.0,0.0,0.5,"fsdf");

//     PLFLT x1,x2,y1,y2;
//     pls->gvpd(x1,y1,x2,y2);
//     pls->gspa(x1,y1,x2,y2);
//     wxLogDebug(_("%f %f %f %f"),x1,x2,y1,y2);


  RenewPlot();
}



// void MuniPlotHisto::OnSize(wxSizeEvent& event)
// {
//   wxLogDebug(wxT("MuniPlotHisto::OnSize"));
//   //  Plot();
//   event.Skip();
// }




// --- MuniPlotTable -------------------------------------

MuniPlotTable::MuniPlotTable(const vector<wxRealPoint>& p,const wxColour& c):
  points(p),colour(c)
{
}


// --- MuniPlot ------------------------------------------


MuniPlot::MuniPlot(wxWindow *w):
  wxPLplotwindow(w,wxID_ANY,wxDefaultPosition,wxDefaultSize,wxWANTS_CHARS,
		 PLPLOT_OPTIONS),
		 //		 wxPLPLOT_BACKEND_GC|wxPLPLOT_DRAW_TEXT|wxPLPLOT_SMOOTH_TEXT),
  xmin(numeric_limits<double>::max()),xmax(numeric_limits<double>::min()),
  ymin(numeric_limits<double>::max()),ymax(numeric_limits<double>::min())
{
  Draw();
}

void MuniPlot::AddData(const MuniPlotTable& t)
{
  for(size_t i = 0; i < t.points.size(); i++) {
    wxRealPoint p(t.points[i]);
    if( p.x < xmin ) xmin = p.x;
    if( p.x > xmax ) xmax = p.x;
    if( p.y < ymin ) ymin = p.y;
    if( p.y > ymax ) ymax = p.y;
  }

  tables.push_back(t);
  Draw();
}



void MuniPlot::Draw()
{
  wxColour cb = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWFRAME);

  wxPLplotstream* pls = GetStream();
  pls->adv( 0 );
  pls->schr(0.0,3.0);
  //  pls->scol0a(0,255,255,255,1.0);
  pls->scol0a(0,cb.Red(),cb.Green(),cb.Blue(),1.0);
  pls->scol0a(1,0,0,0,1.0);

  if( tables.empty() ) {
    pls->vpor(0.01, 0.99, 0.2, 0.99);
    pls->wind(-0.5, 10.5, 0.0, 1.0);
    pls->box("bcnt",0.0,0.0,"bct",0.0,0.0);
  }
  else {

    pls->scol0a(2,255,0,0,0.2);
    pls->scol0a(3,0,255,0,0.2);
    pls->scol0a(4,0,0,255,0.2);
    pls->scol0a(5,170,170,170,0.2);

    pls->scol0a(12,255,0,0,1.0);
    pls->scol0a(13,0,255,0,1.0);
    pls->scol0a(14,0,0,255,1.0);
    pls->scol0a(15,170,170,170,1.0);
    
    pls->vpor(0.01, 0.99, 0.2, 0.99);
    pls->wind(xmin, xmax, ymin, ymax);
    pls->box("bcnt",0.0,0.0,"bct",0.0,0.0);

  }
  //    const size_t nh = 50;
//   PLFLT         hx[nh],hr[nh],hg[nh],hb[nh];
//     for ( size_t i = 0; i < nh; i++ ) {
//       double t = (i - 25.0)/10.0;
//       hx[i] = t;
//       hr[i] = exp(-(t-1)*(t-1)/2.0);
//       hg[i] = exp(-(t-0)*(t-0)/2.0);
//       hb[i] = exp(-(t+1)*(t+1)/2.0);
//       //      wxLogDebug(_("%f %f"),hx[i],hy[i]);
//     }


  RenewPlot();
}




// Plot Nite

PlotNite::PlotNite(wxWindow *w):
  wxPLplotwindow(w,wxID_ANY,wxDefaultPosition,wxDefaultSize,wxWANTS_CHARS,
		 PLPLOT_OPTIONS),xmin(0.0),xmax(0.0)
{
  Plot();
}

wxSize PlotNite::DoGetBestSize() const
{
  return wxSize(300,185);
}

void PlotNite::SetColor(const FitsColor& c)
{
  color = c;
  Plot();
}

void PlotNite::SetXrange(double x1, double x2)
{
  xmin = x1;
  xmax = x2;
  Plot();
}

void PlotNite::Plot() {

  wxColour cb = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWFRAME);
  wxColour ct = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
  wxColour ht = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNHIGHLIGHT);

  wxPLplotstream* pls = GetStream();
  pls->adv(0);
  pls->schr(0.0,2.0);

  pls->scol0a(0,cb.Red(),cb.Green(),cb.Blue(),1.0);
  pls->scol0a(1,ct.Red(),ct.Green(),ct.Blue(),1.0);

  pls->vpor(0.1, 0.9, 0.2, 0.9);
  pls->wind(0.95*xmin, 1.05*xmax, 0.0, 1.1);
  pls->box("bcnt",0.0,0.0,"bct",0.0,0.0);

  PLFLT p_xmin, p_xmax, p_ymin, p_ymax;
  pls->gvpw (p_xmin, p_xmax, p_ymin, p_ymax);
  int npoints = 20;
  double step = (p_xmax - p_xmin)/npoints;
  PLFLT x[npoints],y[npoints];
  for(int i = 0; i < npoints; i++) {
    double t = p_xmin + i*step;
    x[i] = t;
    y[i] = color.NightProfile(t);
  }
  pls->scol0a(9,ht.Red(),ht.Green(),ht.Blue(),0.5);
  pls->col0(9);
  pls->wid(3);
  pls->line(npoints,x,y);

  pls->wid(0);
  pls->col0(1);

  RenewPlot();
}
